
SNFIRaid = { } -- public interface

local SNFRaidGroups = { } -- private interface

SNFRaids = { }	-- old data structure, will move away from this
--[[
local lclRaidID = nil

local function InitializeDataRaid(RaidID, leader)

	if not RaidID then return end

	if not SNFRaids then SNFRaids = { } end

	if not SNFRaidGroups then SNFRaidGroups = { } end

	if not SNFRaids[RaidID] then
		SNFRaids[RaidID] = {
			RaidLeader = leader,
			Source = UnitName("player"),
			Authority = 1,  -- TODO if this is the master looter, this should be 0 instead.
			StartTime = nil,
			EndTime = nil,
			StartList = nil,
			EndList = nil,
			WaitList = nil,
		}
	end

	local g = SNFIRaid["group"]
	if g then
		if not SNFRaidGroups[g] then SNFRaidGroups[g] = { } end
		--I think this will allow some compatibility until I've moved everything over.
		SNFRaidGroups[g][RaidID] = SNFRaids[RaidID]
		SNFIRaid["raid"] = RaidID
	end
end

local function GetCurrentRaidMembers()
	local lst = { }
	local n = GetNumRaidMembers()

	for i = 1, n do
		local name, rank, subgroup, level, class, fileName,
		  zone, online, isDead, role, isML = GetRaidRosterInfo(i);
		if subgroup < 6 then
			tinsert(lst,name)
		else
			SNFDEBUG(1, "Skipping raid member "..name.." because in group "..subgroup)
		end
	end
	return lst
end

local function PopulateStartList(RaidID)

	if not SNFRaids[RaidID]["StartList"] then
		SNFRaids[RaidID]["StartList"] = GetCurrentRaidMembers()
	end

	local g = SNFIRaid["group"]
	if g and not SNFRaidGroups[g][RaidID]["StartList"] then
		SNFRaidGroups[g][RaidID]["StartList"] = GetCurrentRaidMembers()
	end
end

local function CalculateWaitList(RaidID)
--TODO
end

local function PopulateEndList()
	if not lclRaidID or not SNFRaids[lclRaidID] then
		SNFDEBUG(0, "There is no raid started!")
		return
	end
	SNFRaids[lclRaidID]["EndList"] = GetCurrentRaidMembers()
	--CalculateWaitList(lclRaidID)
	lclRaidID = nil

	local g = SNFIRaid["group"]
	local r = SNFIRaid["raid"]
	if g then
		if not r then
			SNFDEBUG(0, "There is no raid started (2)!")
			return
		end
		SNFRaidGroups[g][r]["EndList"] = GetCurrentRaidMembers()
		CalculateWaitList(r)
		SNFIRaid["raid"] = nil
	end

end

local function CalcRaidID(RaidID)

	if RaidID then
		lclRaidID = RaidID
		return
	end
	if not IsInInstance() then
		SNFDEBUG(0, "You must initiate the raid from within the instance!");
		return nil
	end
	local zone = GetRealZoneText()
	if not zone then
		SNFDEBUG(0, "Could not find zone string - can't start raid.");
		return nil
	end
	local lcldate = date("%Y%m%d")
	if not lcldate then
		SNFDEBUG(0, "Date string won't format - can't start raid.");
		return nil
	end
	lclRaidID = zone.."_"..lcldate
	return lclRaidID
end


local function tcontains(table, name)
	for _, val in ipairs(table) do
		if val == name then return true end
	end
	return false
end

local function tcontainsplayer(table, name)

	-- Make sure name is translated before it's passed into this method.
	for _, val in ipairs(table) do

--		SNFDEBUG(2, "Checking SNFPlayer:GetPlayerMain("..(val or "nil")..") = "..SNFPlayer:GetPlayerMain(val).." to "..name)
		if SNFPlayer:GetPlayerMain(val) == name then return true end
	end
	return false
end


-- PUBLIC METHODS

function SNFIRaid:SetRaidGroup(group)

	if not group or group == "" then
		SNFDEBUG(0, "Failed to set empty raid group")
		return false
	end
	SNFIRaid["group"] = group
	return true
end

function SNFIRaid:SetCurrentRaid(raid)

	if not raid or raid == "" then
		SNFDEBUG(0, "Invalid RaidID, set failed")
		return false
	end
	SNFIRaid["raidid"] = raid
	return true
end

function SNFIStartRaid(leader, sendMessage)

	if not leader or leader == "" then
		SNFDEBUG(0, "Invalid leader - start raid failed")
		return false
	end
	--continue here
end
-- need to get rid of sendmessage, it's not used anymore
function SNFStartRaid(r, leader, sendMessage)

--	CalcRaidID(r)

	if not r or r == "" then
		SNFDEBUG(0,"Raid ID is null - aborting")
		return
	end
	InitializeDataRaid(r, leader)
	SNFUIUpdateRaidID(r)
	SNFUIRaidStarted()

	lclRaidID = r -- hack, needs to go away eventually WHSTODO
	SNFIRaid["raid"] = r
	if not SNFRaids[r] then
		SNFDEBUG(0, "Raid not initialized properly!")
		return ""
	end
	hours,minutes = GetGameTime();
	if not SNFRaids[lclRaidID]["StartTime"] then -- Don't overwrite if it already exists
		SNFRaids[lclRaidID]["StartTime"] = hours..":"..minutes
	end
	local g = SNFIRaid["group"]
	--local r = SNFIRaid["raid"]
	if g then
		if not r then
			SNFDEBUG(0, "There is no raid started (2)!")
			return
		end
		if not SNFRaidGroups[g][r]["StartTime"] then -- Don't overwrite if it already exists
			SNFRaidGroups[g][r]["StartTime"] = hours..":"..minutes
		end
	end
	PopulateStartList(r)
	SNFInitializeDataAuction(r)  -- resets LastAuctionNumber
--	SendChatMessage("Raid Started. Whisper me 'wl add' to get on the wait list.", "GUILD" )
	return r
end

function SNFEndRaid()
	hours,minutes = GetGameTime();

	local r = SNFIRaid["raid"]
	if not r then
		SNFDEBUG(0, "Can't end a raid when one isn't started!")
		return
	end
	local g = SNFIRaid["group"]

	SNFRaids[lclRaidID]["EndTime"] = hours..":"..minutes  -- this doesn't work with gropus for some reason - look into it.  WHSTODO
	PopulateEndList()
--	SNFDEBUG(0, "Raid end taken")
	SendChatMessage("Raid end has been taken, you may now leave the raid", "GUILD" )
	SNFUIRaidEnded()
end

function SNFDKP_ListRaids()

	table.sort(SNFRaids)
	local srt

	local srt = { }
	for raidid, _ in pairs(SNFRaids) do
		table.insert(srt, raidid)
	end
	table.sort(srt)

	for _, raidid in ipairs(srt) do
		local data = SNFRaids[raidid]
		SNFDEBUG(0, "["..raidid.."] from "..(data["Source"] or ""))
	end
end

function SNFDKP_GetRaidMembers(raid, whichlist)

	SNFDEBUG(1, "Dumping raid to UI: "..raid)

	if SNFRaids and SNFRaids[raid] then
		return SNFRaids[raid][whichlist]
	end
	return nil
end

function SNFDKP_ListRaidMembers(raid)

	local which = raid or lclRaidID or ""

	local closed = "open"
	if SNFRaids[lclRaidID] and SNFRaids[lclRaidID]["WaitListClosed"] then
		closed = "closed"
	end
	SNFDEBUG(1, "Dumping raid: "..which..".  Wait list is "..closed)

	if SNFRaids and SNFRaids[which] then
		local start = "[none]"
		if SNFRaids[which]["StartList"] then
			start = ""
			for _, name in pairs(SNFRaids[which]["StartList"]) do
				start = start..name..", "
			end
			--start = strjoin(", ", SNFRaids[which]["StartList"])
		end
		SNFDEBUG(0, "Start raid: "..start);

		local endlist = "[none]"
		if SNFRaids[which]["EndList"] then
			endlist = ""
			for _, name in pairs(SNFRaids[which]["EndList"]) do
				endlist = endlist..name..", "
			end
			--endlist = strjoin(", ", SNFRaids[which]["EndList"])
		end
		SNFDEBUG(0, "End raid: "..endlist);

		local wait = "[none]"
		local late = ""
		if SNFRaids[which]["WaitList"] then
			wait = ""
			for _, name in pairs(SNFRaids[which]["WaitList"]) do
				wait = wait..name..", "
			end
			local init = false
			if (SNFRaids[which]["LateWait"]) then
				for _, name in pairs(SNFRaids[which]["LateWait"]) do
					if not init then
						late = " Late: "
						init = true
					end
					late = late..name..", "
				end
			end
			--wait = strjoin(", ", SNFRaids[which]["WaitList"])
		end

		SNFDEBUG(0, "Wait raid: "..wait..late);
	end
end

function SNFDeleteRaid(r)

	SNFDeleteRaidAuctions(r)
	if SNFRaids and r and SNFRaids[r] then
		SNFRaids[r] = nil
		SNFDEBUG(0, "Raid "..r.." deleted!")
	end
	local g = SNFIRaid["group"]
	if g and SNFRaidGroups[g] and SNFRaidGroups[g][r]then
		SNFRaidGroups[g][r] = nil
		SNFDEBUG(0, "Raid "..r.." deleted! (2)")
	end
end

function SNFWaitListAdd(sender)

	local who = SNFPlayer:GetPlayerMain(sender)

	if not lclRaidID then -- no raid started
		SendChatMessage("Raid is not started yet - wait for someone to announce in guild chat", "WHISPER", nil, sender)
		return false
	end

	if SNFRaids and lclRaidID and SNFRaids[lclRaidID] then
		if not SNFRaids[lclRaidID]["WaitList"] then
			SNFRaids[lclRaidID]["WaitList"] = { }
		end

		local thelist = SNFRaids[lclRaidID]["WaitList"]

		for i, name in ipairs(thelist) do
			if thelist[i] == who then
				SendChatMessage("You're already on the wait list!", "WHISPER", nil, sender)
				return false -- skip if already in the list
			end
		end
		local latewaiting = false
		if (SNFRaids[lclRaidID]["WaitListClosed"]) then
			if not SNFRaids[lclRaidID]["LateWait"] then
				SNFRaids[lclRaidID]["LateWait"] = { }
			end
			thelist = SNFRaids[lclRaidID]["LateWait"]
			latewaiting = true
		end

		for i, name in ipairs(thelist) do
			if thelist[i] == who then
				SendChatMessage("You're already on the wait list!", "WHISPER", nil, sender)
				return false-- skip if already in the list
			end
		end
		if latewaiting then
			SendChatMessage("Wait List is closed - you will not get wait list credit", "WHISPER", nil, sender)
			SendChatMessage("If you are called to fill in, you may get end raid credit.", "WHISPER", nil, sender)
		end

		tinsert(thelist, who)
		return true
	end
end

function SNFWaitListRemove(sender)

	local who = SNFPlayer:GetPlayerMain(sender)

	if SNFRaids and lclRaidID and SNFRaids[lclRaidID] then
		if SNFRaids[lclRaidID]["WaitList"] then
			for i, name in ipairs(SNFRaids[lclRaidID]["WaitList"]) do
				if SNFRaids[lclRaidID]["WaitList"][i] == who then
					tremove(SNFRaids[lclRaidID]["WaitList"], i)
				end
			end
		end
		if SNFRaids[lclRaidID]["LateWait"] then
			for i, name in ipairs(SNFRaids[lclRaidID]["LateWait"]) do
				if SNFRaids[lclRaidID]["LateWait"][i] == who then
					tremove(SNFRaids[lclRaidID]["LateWait"], i)
				end
			end
		end
	end
end

function SNFSetRaidSum(raidid, leader, source, auth, starttime, endtime)

	SNFDEBUG(4, "SNFSyncRaid()")

	local g = SNFIRaid["group"]
	if not g then SNFDEBUG(0, "Please define a raid group to enable synchronization."); return end
	local r = SNFRaidGroups[g][raidid]
	if not r then
		SNFDEBUG(0, "Raid "..(raidid or "nil").." doesn't exist, adding raid")
		SNFRaidGroups[g][raidid] = { }
		r = SNFRaidGroups[g][raidid]
	end
	if r["RaidLeader"] and leader ~= r["RaidLeader"] then
		SNFDEBUG(1, "Raid Leader mismatch, aborting sync of raid "..raidid)
		return
	end
	if r["Authority"] and tonumber(auth) < tonumber(r["Authority"]) then -- WHSTODO string to number error on this line
		SNFDEBUG(1, "Authority of sync is less than existing, aborting sync")
		return
	end
	r["RaidLeader"] = leader
	r["Source"] = source
	r["Authority"] = tonumber(auth)
	r["StartTime"] = starttime
	r["EndTime"] = endtime
end

function SNFAddRaidList(raidid, whichlist, listdata)
	SNFDEBUG(4, "SNFAddRaidList("..(whichlist or "nil")..","..(listdata or "nil")..")")

	local g = SNFIRaid["group"]
	if not g then SNFDEBUG(0, "Please define a raid group to enable synchronization."); return end
	local work = listdata

	if not SNFRaidGroups[g][raidid] then SNFRaidGroups[g][raidid] = { } end

	local r = SNFRaidGroups[g][raidid]

	if not r[whichlist] then r[whichlist] = { } end

	while (work and work ~= "") do
		local item, rest = strmatch(work, "(.-),(.*)")
		if (item) then
			--SNFDEBUG(2, "Found item: "..(item or "nil"))
			if not tcontains(r[whichlist], item) then
				table.insert(r[whichlist], item)
			end
			work = rest
		end
	end
end

function SNFListRaidsAttended(name)

	local msg
	local inraid

	if not name then
		SNFDEBUG(0, "Can't search for empty names in raid lists")
		return false
	end

	local realname = SNFPlayer:GetPlayerMain(name)

	if realname ~= name then
		SNFDEBUG(0, name.." ("..realname..") shows up in these raids:")
	else
		SNFDEBUG(0, name.." shows up in these raids:")
	end
	local nRaids = 0
	local nAttend = 0

	local srt = SNFFilter:GetFilteredList("attend", true)

	for _, raidid in ipairs(srt) do
		local data = SNFRaids[raidid]
		local count = 0
		msg = ""
		inraid = false
		if data and data["StartList"] and tcontainsplayer(data["StartList"], realname) then
			msg = msg.."|cFFFFFF00S|r"
			inraid = true
			count = count + 1
			if count > 2 then count = 2 end
		else
			msg = msg.."|cFFFF0000S|r"
		end
		if data and data["EndList"] and tcontainsplayer(data["EndList"], realname) then
			msg = msg.."|cFFFFFF00E|r"
			inraid = true
			count = count + 1
			if count > 2 then count = 2 end
		else
			msg = msg.."|cFFFF0000E|r"
		end
		if data and data["WaitList"] and tcontainsplayer(data["WaitList"], realname) then
			msg = msg.."|cFFFFFF00W|r"
			inraid = true
			count = 2
		else
			--msg = msg.."|cFFFF0000W|r"
		end
		msg = raidid..": "..msg
		SNFDEBUG(0, msg)
		if count > 0 then
			nRaids = nRaids + 1
		end
		if count > 1 then
			nRaids = nRaids + 1
		end
		nAttend = nAttend + 2
	end
	SNFDEBUG(0, "Raids = "..(nRaids / 2).." of "..(nAttend / 2).." which is "..(nRaids / nAttend * 100).."%.")
	SNFDEBUG(0, "DKP Total = "..(nRaids))
end

-- This is a quick and dirty way to code this (copied from ListRaidsAttended)
-- needs to be streamlined and/or use cached data
function SNFGetRaidsAttended(name)

	local msg
	local inraid

	if not name then
		SNFDEBUG(1, "Can't search for empty names in raid lists")
		return false
	end
	local realname = SNFPlayer:GetPlayerMain(name)

	if realname ~= name then
		SNFDEBUG(0, name.." ("..realname..") shows up in these raids:")
	else
		SNFDEBUG(0, name.." shows up in these raids:")
	end
	local nRaids = 0
	local nAttend = 0

	local srt = SNFFilter:GetFilteredList("attend", false)

	for _, raidid in ipairs(srt) do
		local data = SNFRaids[raidid]

		local count = 0
		msg = ""
		inraid = false
		if data["StartList"] and tcontainsplayer(data["StartList"], realname) then
			msg = msg.."|cFFFFFF00S|r"
			inraid = true
			count = count + 1
			if count > 2 then count = 2 end
		else
			msg = msg.."|cFFFF0000S|r"
		end
		if data["EndList"] and tcontainsplayer(data["EndList"], realname) then
			msg = msg.."|cFFFFFF00E|r"
			inraid = true
			count = count + 1
			if count > 2 then count = 2 end
		else
			msg = msg.."|cFFFF0000E|r"
		end
		if data["WaitList"] and tcontainsplayer(data["WaitList"], realname) then
			msg = msg.."|cFFFFFF00W|r"
			inraid = true
			count = 2
		else
			--msg = msg.."|cFFFF0000W|r"
		end
		msg = raidid..": "..msg
		--SNFDEBUG(0, msg)
		if count > 0 then
			nRaids = nRaids + 1
		end
		if count > 1 then
			nRaids = nRaids + 1
		end
		nAttend = nAttend + 2
	end
	--SNFDEBUG(0, "Raids = "..(nRaids / 2).." of "..(nAttend / 2).." which is "..(nRaids / nAttend * 100).."%.")
	local attend = (nRaids / nAttend * 100)

	if (attend - floor(attend)) >= .5 then
		return (floor(attend) + 1).."%.", nRaids
	else
		return floor(attend).."%.", nRaids
	end
end

function SNFRaidCloseWait()
	if not lclRaidID then
		SNFDEBUG(2, "No raid set")
		return
	end

	if not SNFRaids[lclRaidID] then
		SNFRaids[lclRaidID] = { }
	end

	if not SNFRaids[lclRaidID]["WaitListClosed"] then
		SNFRaids[lclRaidID]["WaitListClosed"] = true
		SNFDEBUG(0, "Wait list closed - new wl adds go to LateWait list")
		return true
	else
		SNFDEBUG(0, "Wait list is already closed")
	end
	return false
end


function SNFRaidOpenWait()

	if not SNFRaids[lclRaidID] then
		SNFDEBUG(2, "No raid set")
		return false
	end

	if SNFRaids[lclRaidID]["WaitListClosed"] then
		SNFRaids[lclRaidID]["WaitListClosed"] = nil
		SNFDEBUG(0, "Wait list reopened - new wl adds go to Wait list")
		return true
	else
		SNFDEBUG(0, "Wait list is not closed")
	end
	return false
end

function SNFGetRaidData(raidid)

	if raidid and SNFRaids[raidid] then
		return SNFRaids[raidid]
	end
	local g = SNFIRaid["group"]

	if raidid and g and SNFRaidGroups[g][raidid] then
		return SNFRaidGroups[g][raidid]
	end
	return { }
end

function SNFGetFullAttendanceReport(filterit)


	local inraid

	local nRaids = 0
	local attendList = { }

	local srt = SNFFilter:GetFilteredList("attend", false)

	--local stopme = 0

	for _, raidid in ipairs(srt) do

	--if stopme == 0 then
		--SNFDEBUG(2, "Scanning raid "..(raidid or "nil"))
		local data = SNFRaids[raidid]
		local checklst = { }
		local raidscope = false

		if data["StartList"] and type(data["StartList"]) == "table" then
			for _, p in ipairs(data["StartList"]) do

				if not checklst[p] then checklst[p] = { } end
				checklst[p]["count"] = (checklst[p]["count"] or 0) + 1
				if checklst[p]["count"] > 2 then checklst[p]["count"] = 2 end

				--SNFDEBUG(3, "grabbing info from StartList for "..p.." count is "..(checklst[p]["count"] or "nil"))
				raidvalid = true
			end
		end

		if data["EndList"] and type(data["EndList"]) == "table" then
			for _, p in ipairs(data["EndList"]) do

				if not checklst[p] then checklst[p] = { } end
				checklst[p]["count"] = (checklst[p]["count"] or 0) + 1
				if checklst[p]["count"] > 2 then checklst[p]["count"] = 2 end
				--SNFDEBUG(3, "grabbing info from StartList for "..p.." count is "..(checklst[p]["count"] or "nil"))
				raidvalid = true
			end
		end

		if data["WaitList"] and type(data["WaitList"]) == "table" then
			for _, p in ipairs(data["WaitList"]) do

				if not checklst[p] then checklst[p] = { } end
				checklst[p]["count"] = (checklst[p]["count"] or 0) + 1
				checklst[p]["count"] = 2
				--SNFDEBUG(3, "grabbing info from StartList for "..p.." count is "..(checklst[p]["count"] or "nil"))
				raidvalid = true
			end
		end

		if raidvalid then
			nRaids = nRaids + 2
		end

		for p, d in pairs(checklst) do
			--SNFDEBUG(3, "grabbing info from checklst for "..p.." count is "..(d["count"] or "nil"))
			if not attendList[p] then attendList[p] = { } end
			attendList[p]["count"] = (attendList[p]["count"] or 0) + d["count"]
		end
	--stopme = 1
	--end
	end

	-- gonna need to sort names first, then show sorted list that way.  Perhaps even sort by initiate/raider WHSTODO
	--table.sort(attendList, function(a,b) return (a["count"] < b["count"]) end)

	for p, d in pairs(attendList) do

		local attend = ((d["count"] or 0) / nRaids * 100)
		local att = ""

		if (attend - floor(attend)) >= .5 then
			att =  (floor(attend) + 1).."%."
		else
			att =  floor(attend).."%."
		end

		local abbrev = SNFGetPlayerRankAbbreviation(p)
		if (not filterit) or (abbrev == "R" or abbrev == "I" or abbrev == "V") then
			SNFDEBUG(0, abbrev.." "..(p or "Nil").." attends "..att)
		end
	end

	SNFDEBUG(0, "Total number of raids: "..(nRaids or 0) / 2)
end
]]--
